package
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.BlendMode;
    import flash.display.GradientType;
    import flash.display.Shape;
    import flash.filters.BlurFilter;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.utils.Endian;

    public class Environment
    {
        public static var MIN_RADIUS : Number = 200;

        var bdToxic : BitmapData;
        var bdNutrients : BitmapData;
        var bdFluidity : BitmapData;

        public function Environment()
        {

        }

        public function subtractNutrients(x : Number, y : Number, radius : Number, amount : Number) : void
        {
            var shape : Shape = new Shape();

            var mat : Matrix = new Matrix();

            mat.createGradientBox(radius * 2, radius * 2, 0, 0, 0);

            shape.graphics.beginGradientFill(GradientType.RADIAL, [uint(255 * amount) << 8, 0], [100, 0], [0, 0xAA], mat);
            shape.graphics.drawEllipse(0, 0, radius * 2, radius * 2);
            shape.graphics.endFill();

            var mat2 : Matrix = new Matrix();
            mat2.tx = x - radius;
            mat2.ty = y - radius;

            bdNutrients.draw(shape, mat2, null, BlendMode.SUBTRACT);
        }

        public function subtractToxins(x : Number, y : Number, radius : Number, amount : Number) : void
        {
            var shape : Shape = new Shape();

            var mat : Matrix = new Matrix();

            mat.createGradientBox(radius * 2, radius * 2, 0, 0, 0);

            shape.graphics.beginGradientFill(GradientType.RADIAL, [uint(255 * amount) << 16, 0], [100, 0], [0, 0xAA], mat);
            shape.graphics.drawEllipse(0, 0, radius * 2, radius * 2);
            shape.graphics.endFill();

            var mat2 : Matrix = new Matrix();
            mat2.tx = x - radius;
            mat2.ty = y - radius;

            bdToxic.draw(shape, mat2, null, BlendMode.SUBTRACT);
        }

        public function generateEnvironment(toxicCells : Number, nutrientCells : Number, fluidCells : Number, toxicBase : uint = 0x20, nutrientBase : uint = 0x20, fluidBase : uint = 0x20) : void
        {
            bdToxic = new BitmapData(800, 600, false, toxicBase << 16);
            bdNutrients = new BitmapData(800, 600, false, nutrientBase << 8);
            bdFluidity = new BitmapData(800, 600, false, fluidBase);

            // First we generate toxic cells.
            var tc : Array = new Array(toxicCells);

            for (var i : int = 0; i < toxicCells; i++)
            {
                tc[i] = {pow: (Math.random() * 0.3) + 0.7, x: Math.random() * 800, y: Math.random() * 600, w: MIN_RADIUS + Math.random() * 500, h: MIN_RADIUS + Math.random() * 500};

                var tcShape : Shape = new Shape();

                var mat : Matrix = new Matrix();

                mat.createGradientBox(tc[i].w, tc[i].h, 0, 0, 0);

                tcShape.graphics.beginGradientFill(GradientType.RADIAL, [uint(255 * tc[i].pow) << 16, toxicBase << 16], [100, 0], [0, 0xAA], mat);
                tcShape.graphics.drawEllipse(0, 0, tc[i].w, tc[i].h);
                tcShape.graphics.endFill();

                var mat2 : Matrix = new Matrix();
                mat2.tx = tc[i].x - tc[i].w / 2;
                mat2.ty = tc[i].y - tc[i].h / 2;

                bdToxic.draw(tcShape, mat2);
            }

            // Second we generate Nutrient cells.
            var nc : Array = new Array(nutrientCells);

            for (var i : int = 0; i < nutrientCells; i++)
            {
                nc[i] = {pow: (Math.random() * 0.3) + 0.7, x: Math.random() * 800, y: Math.random() * 600, w: MIN_RADIUS + Math.random() * 500, h: MIN_RADIUS + Math.random() * 500};

                var ncShape : Shape = new Shape();

                var mat : Matrix = new Matrix();

                mat.createGradientBox(nc[i].w, nc[i].h, 0, 0, 0);

                ncShape.graphics.beginGradientFill(GradientType.RADIAL, [uint(255 * nc[i].pow) << 8, nutrientBase << 8], [100, 0], [0, 0xAA], mat);
                ncShape.graphics.drawEllipse(0, 0, nc[i].w, nc[i].h);
                ncShape.graphics.endFill();

                var mat2 : Matrix = new Matrix();
                mat2.tx = nc[i].x - nc[i].w / 2;
                mat2.ty = nc[i].y - nc[i].h / 2;

                bdNutrients.draw(ncShape, mat2);
            }

            // Third we generate Fluidity cells.
            var fc : Array = new Array(fluidCells);

            for (var i : int = 0; i < fluidCells; i++)
            {
                fc[i] = {pow: (Math.random() * 0.3) + 0.7, x: Math.random() * 800, y: Math.random() * 600, w: MIN_RADIUS + Math.random() * 500, h: MIN_RADIUS + Math.random() * 500};

                var fcShape : Shape = new Shape();

                var mat : Matrix = new Matrix();

                mat.createGradientBox(fc[i].w, fc[i].h, 0, 0, 0);

                fcShape.graphics.beginGradientFill(GradientType.RADIAL, [uint(255 * fc[i].pow), fluidBase], [100, 0], [0, 0xAA], mat);
                fcShape.graphics.drawEllipse(0, 0, fc[i].w, fc[i].h);
                fcShape.graphics.endFill();

                var mat2 : Matrix = new Matrix();
                mat2.tx = fc[i].x - fc[i].w / 2;
                mat2.ty = fc[i].y - fc[i].h / 2;

                bdFluidity.draw(fcShape, mat2);
            }

            var blur : BlurFilter = new BlurFilter(10, 10, 3);

            bdToxic.applyFilter(bdToxic, bdToxic.rect, new Point(0, 0), blur);
            bdNutrients.applyFilter(bdNutrients, bdNutrients.rect, new Point(0, 0), blur);
            bdFluidity.applyFilter(bdFluidity, bdFluidity.rect, new Point(0, 0), blur);
        }
    }
}